use super::{deserialize_json, serialize_json};
use crate::pool;
use rbatis::{crud, impl_select_page, Page, rbdc::{self, db::ExecResult}, sql::{self, PageRequest}};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TbRole {
    pub id: Option<u64>,
    pub name: String,
    #[serde(
    serialize_with = "serialize_json",
    deserialize_with = "deserialize_json"
    )]
    pub menu_ids: Option<Vec<u64>>,
    #[serde(
    serialize_with = "serialize_json",
    deserialize_with = "deserialize_json"
    )]
    pub api_ids: Option<Vec<u64>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Role {
    pub id: Option<u64>,
    pub name: String,
    pub menu_ids: Option<Vec<u64>>,
    pub api_ids: Option<Vec<u64>>,
}

impl From<TbRole> for Role {
    fn from(value: TbRole) -> Self {
        Self {
            id: value.id,
            name: value.name,
            menu_ids: value.menu_ids,
            api_ids: value.api_ids,
        }
    }
}

impl From<Role> for TbRole {
    fn from(value: Role) -> Self {
        Self {
            id: value.id,
            name: value.name,
            menu_ids: value.menu_ids,
            api_ids: value.api_ids,
        }
    }
}

crud!(TbRole {});
impl_select_page!(TbRole {select_page(query: &crate::handlers::role::Get) =>
    "`where 1=1`
    if query.id!=null:
        ` and id=#{query.id}`
    if query.name!=null && query.name!='':
        ` and name like #{'%'+query.name+'%'}`
    ` order by id asc`"
});

impl TbRole {
    pub async fn get_roles(
        page: &crate::common::QueryPage,
        query: &crate::handlers::role::Get,
    ) -> Result<Page<TbRole>, rbdc::Error> {
        TbRole::select_page(pool!(), &PageRequest::from(page), query).await
    }

    pub async fn get_all_role() -> Result<Vec<TbRole>, rbdc::Error> {
        TbRole::select_all(pool!()).await
    }

    pub async fn insert_role(data: &mut TbRole) -> Result<ExecResult, rbdc::Error> {
        let result = TbRole::insert(pool!(), data).await?;
        data.id = Some(result.last_insert_id.clone().into());
        Ok(result)
    }

    pub async fn update_role(data: &TbRole) -> Result<ExecResult, rbdc::Error> {
        TbRole::update_by_column(pool!(), data, "id").await
    }

    pub async fn delete_role(id: u64) -> Result<ExecResult, rbdc::Error> {
        TbRole::delete_by_column(pool!(), "id", id).await
    }
}

#[cfg(test)]
mod tests {
    use crate::tables::role::TbRole;

    #[test]
    fn test_make_table() {
        let table = rbatis::make_table!(TbRole { id: Some(1) });
        println!("table {:#?}", table);
        let table_vec = vec![table];
        let map = rbatis::make_table_field_map!(&table_vec, id);
        println!("map {:#?}", map);
        let parent_ids = rbatis::make_table_field_vec!(&table_vec, id);
        println!("vec {:#?}", parent_ids);
    }
}
